home *** CD-ROM | disk | FTP | other *** search
/ Sound Fx / Sound Fx.iso / Software / UNZIPED / SBPLY254 / SOURCE.ZIP / _PCPLAY.ASM < prev    next >
Assembly Source File  |  1996-04-26  |  13KB  |  429 lines

  1. _TEXT   SEGMENT WORD PUBLIC 'CODE'
  2. _TEXT   ENDS
  3.  
  4. _DATA SEGMENT WORD PUBLIC 'DATA'        
  5. _DATA   ENDS
  6.  
  7. CONST   SEGMENT WORD PUBLIC 'CONST'
  8. CONST   ENDS
  9.  
  10. _BSS    SEGMENT WORD PUBLIC 'BSS'
  11. ;GLOBAL UNINITIATED DATA GOES HERE
  12. _BSS    ENDS
  13.  
  14. DGROUP  GROUP CONST,_BSS,_DATA
  15. ;
  16.         ASSUME DS:DGROUP,SS:DGROUP
  17.  
  18. ;EXTRN EXTERNAL SUBROUTINE CALLS GO HERE
  19. ;
  20. ; _pcplay FAR Procedure for C Written by John A. Ball  April 22, 1996
  21. ;
  22. ;Plays back sound on the regular pc speaker
  23. ;
  24. ;       void     pcplay(char *buffer,unsigned number_read,unsigned frequency
  25. ;                       ,unsigned volume);
  26. ;
  27. ;       pcplay(Buffer Pointer,Length,Frequency,Volume);
  28. ;
  29. ;       Buffer Pointer is a Far pointer to the sound buffer (64k max)
  30. ;       Length is the number of sound samples to play
  31. ;       Frequency is the playback frequency in hertz
  32. ;       Volume is currently not supported
  33. ;
  34. _TEXT   SEGMENT
  35.         ASSUME CS:_TEXT
  36.         PUBLIC _pcplay
  37.                 
  38. _pcplay PROC FAR
  39.  
  40. PARMA           EQU [BP+6]      ;Sound Buffer Pointer
  41. PARMB           EQU [BP+10]     ;Number of samples to play (Length)
  42. PARMC           EQU [BP+12]     ;Frequency to playback samples
  43. PARMD           EQU [BP+14]     ;Volume 0-7
  44. PARMS           EQU 10          ;Number of bytes for local storage
  45.  
  46. BUFFERPNT       EQU [BP-4]      ;LOCAL VARIABLES GO HERE
  47. SAMPLES         EQU [BP-6]
  48. FREQUENCY       EQU [BP-8]
  49. VOLUME          EQU [BP-10]
  50.  
  51.         PUSH BP                 ;Save stack Frame
  52.         MOV BP,SP
  53.         SUB SP,PARMS            ;MAKE SPACE FOR LOCAL VARIABLE (INT) ON STACK
  54.         PUSH DS                 ;Save registers
  55.         PUSH ES
  56.         PUSH SI
  57.         PUSH DI
  58.     MOV CS:ERROR,0          ;Initialize error
  59.         JMP OVERDATA
  60.  
  61. DDELAY          DW 0
  62. TCOUNT          DW 0
  63. MCOUNT          DW 0
  64. LCOUNT          DW 0
  65. PERIOD          DW 0
  66. DOUBLER         DW 0
  67. ERROR           DW 0
  68.  
  69. TABLE   DB 53,53,53,53,53,52,52,52,52,52,52,52,52,52,52,51
  70.         DB 51,51,51,51,51,51,51,51,50,50,50,50,50,50,50,50
  71.         DB 49,49,49,49,49,49,49,49,49,48,48,48,48,48,48,48
  72.         DB 48,47,47,47,47,47,47,47,46,46,46,46,46,46,46,45
  73.         DB 45,45,45,45,45,45,44,44,44,44,44,44,43,43,43,43
  74.         DB 43,43,42,42,42,42,42,42,41,41,41,41,41,40,40,40
  75.         DB 40,40,39,39,39,39,39,38,38,38,38,37,37,37,37,36
  76.         DB 36,36,35,35,35,34,34,34,33,33,32,32,31,30,29,27
  77.         DB 25,24,23,22,22,21,21,20,20,19,19,19,18,18,18,17
  78.         DB 17,17,17,16,16,16,16,15,15,15,15,14,14,14,14,14
  79.         DB 13,13,13,13,12,12,12,12,12,12,11,11,11,11,11,10
  80.         DB 10,10,10,10,10,9,9,9,9,9,9,9,8,8,8,8
  81.         DB 8,8,7,7,7,7,7,7,7,6,6,6,6,6,6,6
  82.         DB 6,5,5,5,5,5,5,5,4,4,4,4,4,4,4,4
  83.         DB 3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2
  84.         DB 2,2,1,1,1,1,1,1,1,1,1,0,0,0,0,0
  85.  
  86. OVERDATA:
  87.         LES DI,PARMA            ;GET SOUND BUFFER POINTER
  88.         MOV BUFFERPNT,DI        ;AND SAVE
  89.         MOV DI,ES
  90.         MOV BUFFERPNT+2,DI
  91.         
  92.         MOV BX,PARMB            ;Get number of samples
  93.     CMP BX,0                ;Check for zero samples
  94.     JNE NORESET
  95.     MOV CS:DDELAY,0         ;Reset delay if zero samples
  96.     JMP FINISHED
  97. NORESET:
  98.         MOV SAMPLES,BX          ;AND SAVE
  99.  
  100.         MOV CS:DOUBLER,0
  101.         MOV BX,PARMC            ;Get frequency
  102.         CMP BX,0                ;CHECK FOR DIVIDE BY ZERO
  103.         JNE OK0
  104.         MOV BX,11000            ;use default if zero
  105. OK0:
  106.     CMP BX,0FFFFH           ;Is frequency > 32,767 hz?
  107.         JL OK21
  108.         CMP BX,15000            ;Is frequency > 15,000 hz?
  109.         JG OK1
  110.         MOV CS:DOUBLER,2        ;Indicate frequency to be doubled
  111.         SHL BX,1                ;Double frequency for play back
  112. OK1:    CMP BX,22000            ;Is frequency 22,000 hz?
  113.         JL OK2
  114. OK2:    CMP BX,0FFFFH           ;Is frequency 44,000 hz?
  115.         JG OK3
  116. OK21:   MOV CS:DOUBLER,4        ;Indicate frequency to be halved
  117.         SHR BX,1                ;Halve frequency for playback
  118. OK3:    MOV FREQUENCY,BX        ;and save
  119.         MOV DX,000FH            ;CALCULATE PERIOD 1000000/FREQUENCY
  120.         MOV AX,04240H
  121.         DIV BX
  122.         MOV CS:PERIOD,AX
  123. ;
  124. CPUSPEED:        
  125.         CMP CS:DDELAY,0         ;SKIP IF ALREADY DONE
  126.         JE GETSPEED
  127.         JMP BEGIN
  128.  
  129. GETSPEED:
  130.         IN AL,61H               ;DISCONNECT SPEAKER FROM TIMER CHIP
  131.         PUSH AX                 ;SAVE STATUS BITS
  132.         AND AL,11111100B        ;AND STOP TIMER
  133.         OUT 61H,AL
  134.         JMP $+2
  135.         JMP $+2
  136.         MOV AL,0B4H             ;PROGRAM TIMER 2 FOR MODE 2
  137.         OUT 43H,AL
  138.         JMP $+2
  139.         JMP $+2
  140.         MOV AL,0                ;SET TIMER COUNT DOWN MAX COUNT
  141.         OUT 42H,AL
  142.         JMP $+2
  143.         JMP $+2
  144.         MOV AL,00H
  145.         OUT 42H,AL
  146.         JMP $+2
  147.         JMP $+2
  148.  
  149.         POP AX                  ;START TIMER
  150.         PUSH AX
  151.         OR AL,00000001B
  152.         OUT 61H,AL
  153.         JMP $+2        
  154.         POP AX                  ;STOP TIMER
  155.         AND AL,11111100B
  156.         OUT 61H,AL
  157.         JMP $+2        
  158.         IN AL,42H               ;GET TIMER COUNT
  159.         MOV BL,AL
  160.         JMP $+2
  161.         JMP $+2
  162.         IN AL,42H
  163.         MOV BH,AL               ;BX = TIMER COUNT
  164.         MOV AX,0                ;GET NUMBER OF COUNTS USED GETTING THE TIME
  165.         SUB AX,BX
  166.         MOV CS:TCOUNT,AX        ;AND SAVE IT
  167.         
  168.         MOV SI,0
  169.         MOV DI,0
  170.     MOV CX,10               ;TIME for 10 loops
  171.  
  172.         MOV BH,0
  173.         MOV AH,0
  174.  
  175.         CLI                     ;DISABLE INTERRUPTS DURING TEST
  176.  
  177.         IN AL,61H               ;START TIMER
  178.         PUSH AX
  179.         JMP $+2
  180.         OR AL,00000001B
  181.         OUT 61H,AL
  182. ;
  183. ;USE ACTUAL LOOP FOR TIMING BUT DISABLE SPEAKER
  184. ;
  185. FETCH1:   
  186.         LDS BX,BUFFERPNT
  187.         MOV AL,[BX+SI]          ;Get sample
  188.         MOV DI,AX
  189.         MOV AL,CS:TABLE[DI]     ;and convert to 6 bits
  190.         OUT 0E0H,AL             ;use E0h so it doesn't interfere with
  191.         IN AL,0E0H
  192.         OR AL,00000000B         ;PRETEND TO START CLOCK
  193.         OUT 0E0H,AL
  194.         
  195.         PUSH CX                 ;Save number of samples
  196.         MOV CX,1                ;use minimum time
  197. DELAY1:  
  198.         JMP $+2
  199.         LOOP DELAY1
  200.         
  201.         POP CX                  ;restore sample count
  202.         INC SI
  203.         
  204.         IN AL,0E0H
  205.         AND AL,1111111B         ;PRETEND TO TURN OFF CLOCK
  206.         OUT 0E0H,AL
  207.         
  208.         LOOP FETCH1
  209.  
  210.         POP AX                  ;STOP TIMER
  211.         AND AL,11111100B
  212.         OUT 61H,AL
  213.         
  214.         STI                     ;ENABLE INTERUPTS 
  215.  
  216.         IN AL,42H               ;GET TIMER COUNT
  217.         MOV BL,AL
  218.         JMP $+2
  219.         JMP $+2
  220.         IN AL,42H
  221.         MOV BH,AL               ;BX = TIMER COUNT
  222.         MOV AX,0                ;65536 - TIMER COUNT = DURATION COUNT
  223.         SUB AX,BX
  224.     int 3
  225.     nop
  226.         SUB AX,CS:TCOUNT        ;SUBTRACT COUNTS USED GETTING THE TIME
  227.         MOV DX,0
  228.         MOV BX,838
  229.     MUL BX                  ;COUNT X 838 / 10000 = DURATION IN uSECs 100L
  230.     MOV BX,10000
  231.         DIV BX
  232.         MOV BX,AX
  233.         MOV AX,CS:PERIOD        ;FIND OUT HOW MUCH TIME TO WASTE
  234.         SUB AL,BL
  235.         MOV AH,0
  236.         MOV CS:MCOUNT,AX        ;SAVE TIME 
  237.         
  238.         MOV CX,100              ;TIME for 100 loops
  239.         CLI                     ;DISABLE INTERRUPTS DURING TEST
  240.  
  241.         IN AL,61H               ;START TIMER 2 AGAIN
  242.         PUSH AX
  243.         JMP $+2
  244.         OR AL,00000001B
  245.         OUT 61H,AL
  246.  
  247. TIME1:  JMP $+2
  248.         LOOP TIME1
  249.  
  250.         POP AX
  251.         AND AL,11111100B
  252.         OUT 61H,AL
  253.         IN AL,42H               ;GET TIMER COUNT
  254.         MOV BL,AL
  255.         JMP $+2
  256.         JMP $+2
  257.         IN AL,42H
  258.         MOV BH,AL               ;BX = TIMER COUNT
  259.         STI
  260.         MOV DX,0
  261.         MOV AX,0                ;NOTE THAT TIMER RESTARTS AT INIT COUNT
  262.         SUB AX,BX               ;IN MODE 2
  263.         SUB AX,CS:TCOUNT        ;SUBTRACT COUNTS USED GETTING THE TIME
  264.         MOV DX,0
  265.         MOV BX,838
  266.         MUL BX                  ;COUNT X 838 / 1000 = DURATION IN uSECs 100L
  267.         MOV BX,1000
  268.         DIV BX
  269.         MOV CS:LCOUNT,AX        ;SAVE TEMPORARY VALUE
  270.         
  271.         MOV DX,0
  272.         MOV AX,CS:MCOUNT        ;GET TIME TO WASTE        
  273.         MOV BX,100
  274.         MUL BX                  ;AND MULTIPLY BY 100
  275.         MOV DX,0
  276.         MOV BX,CS:LCOUNT        ;AND DIVIDE BY LCOUNT
  277.         CMP BX,0                ;CHECK FOR DIVIDE BY ZERO
  278.         JNE OK
  279.         JMP GETSPEED            ;TRY AGAIN
  280. OK:     DIV BX                  ;TO GET LOOPS REQUIRED
  281.         AND AX,07FFH            ;LIMIT TO REASONABLE VALUE
  282.         MOV CS:DDELAY,AX        ;SAVE LOOP COUNTER VALUE
  283. BEGIN:
  284.         MOV AL,092H             ;COUNTER 2, LSB ONLY, MODE 1, BINARY
  285.         OUT 43H,AL
  286.         MOV SI,0
  287.         MOV DX,0
  288.         MOV AH,0
  289.         MOV CX,SAMPLES          ;GET NUMBER OF SAMPLES TO PLAY
  290.         cli
  291.         CMP CS:DOUBLER,0        ;ADJUST PLAYBACK?
  292.         JE FETCH
  293.         JMP BEGIN1
  294.  
  295. FETCH:   
  296.         LDS BX,BUFFERPNT
  297.         MOV DL,[BX+SI]          ;Get sample
  298.         MOV DI,DX               ;get index to table
  299.         MOV AL,CS:TABLE[DI]     ;and convert sample to timer pulse durations
  300.                                 
  301.         OUT 042H,AL
  302.         IN AL,061H
  303.         OR AL,00000011B         ;START CLOCK
  304.         OUT 061H,AL
  305.         PUSH CX                 ;Save number of samples
  306.         MOV CX,CS:DDELAY        ;GET DELAY LOOP COUNTER
  307. DELAY:  
  308.         JMP $+2
  309.         LOOP DELAY
  310.         
  311.         pop cx                  ;RESTORE SAMPLE COUNT
  312.         INC SI
  313.  
  314.         IN AL,061H
  315.         AND AL,1111110B         ;TURN OFF CLOCK
  316.         OUT 061H,AL
  317.         
  318.         LOOP FETCH              ;AND GO GET NEXT SAMPLE
  319.  
  320.         JMP FINISHED
  321.  
  322. BEGIN1:
  323.     CMP CS:DOUBLER,4        ;Halve playback?
  324.         JE PLAYHALF
  325. FETCH3:   
  326.         LDS BX,BUFFERPNT
  327.         MOV DL,[BX+SI]          ;Get sample
  328.         MOV DI,DX               ;get index to table
  329.         MOV AL,CS:TABLE[DI]     ;and convert sample to timer pulse durations
  330.                                 
  331.         OUT 042H,AL
  332.         IN AL,061H
  333.         OR AL,00000011B         ;START CLOCK
  334.         OUT 061H,AL
  335.         PUSH CX                 ;Save number of samples
  336.         MOV CX,CS:DDELAY        ;GET DELAY LOOP COUNTER
  337. DELAY3:  
  338.         JMP $+2
  339.         LOOP DELAY3
  340.         
  341.         NOP
  342.         NOP
  343.                                 
  344.         IN AL,061H
  345.         AND AL,1111110B         ;TURN OFF CLOCK
  346.         OUT 061H,AL
  347.         
  348.         LDS BX,BUFFERPNT
  349.         MOV DL,[BX+SI]          ;Get sample
  350.         MOV DI,DX               ;get index to table
  351.         MOV AL,CS:TABLE[DI]     ;and convert sample to timer pulse durations
  352.  
  353.         OUT 042H,AL             ;Output sample twice at double frequency
  354.  
  355.         IN AL,061H
  356.         OR AL,00000011B         ;START CLOCK
  357.         OUT 061H,AL
  358.  
  359.         MOV CX,CS:DDELAY        ;GET DELAY LOOP COUNTER
  360. DELAY4:  
  361.         JMP $+2
  362.         LOOP DELAY4
  363.         
  364.         pop cx                  ;RESTORE SAMPLE COUNT
  365.         INC SI
  366.  
  367.         IN AL,061H
  368.         AND AL,1111110B         ;TURN OFF CLOCK
  369.         OUT 061H,AL
  370.         
  371.         LOOP FETCH3             ;AND GO GET NEXT SAMPLE
  372.         
  373.         JMP FINISHED
  374.  
  375. PLAYHALF:   
  376.         SHR CX,1                ;Halve the number of samples
  377. FETCH4:
  378.         LDS BX,BUFFERPNT
  379.         MOV DL,[BX+SI]          ;Get sample
  380.         MOV DI,DX               ;get index to table
  381.         MOV AL,CS:TABLE[DI]     ;and convert sample to timer pulse durations
  382.                                 
  383.         OUT 042H,AL
  384.         IN AL,061H
  385.         OR AL,00000011B         ;START CLOCK
  386.         OUT 061H,AL
  387.         PUSH CX                 ;Save number of samples
  388.         MOV CX,CS:DDELAY        ;GET DELAY LOOP COUNTER
  389. DELAY5:  
  390.         JMP $+2
  391.         LOOP DELAY5
  392.         
  393.         pop cx                  ;RESTORE SAMPLE COUNT
  394.         INC SI                  ;Increment twice to skip sample
  395.         INC SI
  396.  
  397.         IN AL,061H
  398.         AND AL,1111110B         ;TURN OFF CLOCK
  399.         OUT 061H,AL
  400.         
  401.         LOOP FETCH4             ;AND GO GET NEXT SAMPLE
  402.  
  403. FINISHED:        
  404.  
  405.         sti
  406.     MOV AH,01H              ;See if key pressed
  407.     INT 16H
  408.     JZ ALL_DONE
  409. KEY_PRESS:
  410.     MOV AX,0
  411.     INT 16H                 ;Get the pressed key
  412.     CMP AL,1BH              ;See if ESC key hit?
  413.     JNE ALL_DONE
  414.     MOV CS:ERROR,-1         ;Halt output if ESC key pressed
  415. ALL_DONE:
  416.     MOV AX,CS:ERROR         ;Get error
  417.         POP DI
  418.         POP SI
  419.         POP ES                  ;Restore registers
  420.         POP DS
  421.         ADD SP,PARMS            ;RESTORE SP
  422.         POP BP                  ;RESTORE BP
  423.         RET                     ;RETURN FAR
  424.  
  425. _pcplay  ENDP
  426. _TEXT   ENDS        
  427.         END
  428.  
  429.